package com.skt.utils;

import com.skt.config.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Date;

@Component
public class JwtUtil {

    private final PrivateKey privateKey;
    private final PublicKey publicKey;
    private final long accessTokenTTL;   // Access Token 有效期
    private final long refreshTokenTTL;  // Refresh Token 有效期

    @Autowired
    public JwtUtil(JwtProperties jwtProperties) throws Exception {
        // 1. 获取 location 并自动去除 classpath: 前缀（如果存在）
        String location = jwtProperties.getLocation();
        if (location == null || location.trim().isEmpty()) {
            throw new IllegalArgumentException("JWT keystore location must not be null or empty");
        }
        location = location.trim();
        if (location.startsWith("classpath:")) {
            location = location.substring("classpath:".length());
        }

        // 2. 加载 JKS 密钥库
        KeyStore keyStore = KeyStore.getInstance("JKS");
        try (InputStream is = new ClassPathResource(location).getInputStream()) {
            keyStore.load(is, jwtProperties.getPassword().toCharArray());
        }

        // 3. 获取私钥（用于签发 Token）
        this.privateKey = (PrivateKey) keyStore.getKey(jwtProperties.getAlias(), jwtProperties.getPassword().toCharArray());

        // 4. 获取公钥（用于验证 Token）
        Certificate cert = keyStore.getCertificate(jwtProperties.getAlias());
        this.publicKey = cert.getPublicKey();

        // 5. 解析双 Token 有效期
        this.accessTokenTTL = parseTTL(jwtProperties.getTokenTTL(), 7200000L);     // 默认2小时
        this.refreshTokenTTL = parseTTL(jwtProperties.getRefreshTokenTTL(), 604800000L); // 默认7天
    }

    // 生成 Access Token（短期令牌）
    public String generateAccessToken(String subject) {
        return generateToken(subject, accessTokenTTL);
    }

    // 生成 Refresh Token（长期令牌）
    public String generateRefreshToken(String subject) {
        return generateToken(subject, refreshTokenTTL);
    }

    // 通用 Token 生成方法（支持自定义过期时间）
    public String generateToken(String subject, long ttlMillis) {
        return Jwts.builder()
                .setSubject(subject)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + ttlMillis))
                .signWith(privateKey)
                .compact();
    }

    // 保持向后兼容的方法（使用 Access Token 的 TTL）
    public String generateToken(String subject) {
        return generateAccessToken(subject);
    }

    // 从 Token 中提取用户名（subject）
    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(publicKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    // 验证 Token（签名 + 过期时间）
    public boolean validateToken(String token) {
        try {
            Jws<Claims> claims = Jwts.parserBuilder()
                    .setSigningKey(publicKey)
                    .build()
                    .parseClaimsJws(token);
            return !claims.getBody().getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    // 解析 TTL 字符串（支持 s/m/h/d），带默认值
    private long parseTTL(String ttl, long defaultValue) {
        if (ttl == null || ttl.isEmpty()) {
            return defaultValue;
        }

        String valueStr = ttl.replaceAll("[^0-9]", "");
        String unit = ttl.replaceAll("[0-9]", "").toLowerCase().trim();

        if (valueStr.isEmpty()) {
            return defaultValue;
        }

        long num = Long.parseLong(valueStr);
        return switch (unit) {
            case "s" -> Duration.of(num, ChronoUnit.SECONDS).toMillis();
            case "m" -> Duration.of(num, ChronoUnit.MINUTES).toMillis();
            case "h" -> Duration.of(num, ChronoUnit.HOURS).toMillis();
            case "d" -> Duration.of(num, ChronoUnit.DAYS).toMillis();
            default -> num; // 默认视为毫秒
        };
    }

    // 添加获取公钥的方法
    public PublicKey getPublicKey() {
        return this.publicKey;
    }

    // 添加解析Claims的方法
    public Claims parseClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(publicKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}